/*************************************************************************
 * @file src/httplib/client.go
 * @auth wuwei
 * @created_time 2018/11/ 2
 * @brief
 ************************************************************************/

package httplib

/*
#include <stdio.h>
#include <stdlib.h>
typedef void (*pfCallBack)(int, int, char*, int);
int DealRequestCallback(void* pfunc, int anHandle, int anStatus, char* aszData, int anLen) {
    pfCallBack pf = (pfCallBack)pfunc;
    pf(anHandle, anStatus, aszData, anLen);
    free(aszData);
    return 0;
}
*/
import "C"

import (
    "sync"
    "time"
    "net/http"
    "log"
    "io/ioutil"
    "strings"
    "unsafe"
)

const (
    enum_handle_type_client         = 1
    enum_handle_type_server         = 2
)

type HandleCache struct {
    handle          int32
    CreateTime      time.Time
    handleType      int32
    Error           error
    status          int
    Req             *http.Request
    Result          []byte
    LenTotal        int32
    CallBack        unsafe.Pointer
}

var g_mapHandle map[int32]*HandleCache
var g_mapLock   sync.Mutex
var g_chanEvent chan *HandleCache
var g_chanCount chan int            // limit max request count
var g_client *http.Client


func init() {
    g_mapHandle = make(map[int32]*HandleCache)
    g_chanEvent = make(chan *HandleCache, 3000)
    g_chanCount = make(chan int, 3000)
    g_client = &http.Client{}
}

func NewHandle(anHandle int32, req *http.Request, anType int32, callback unsafe.Pointer) *HandleCache {
    cache := &HandleCache{}
    cache.handle = anHandle
    cache.Req = req
    cache.handleType = anType
    cache.CallBack = callback
    return cache
}

func WaitForEvent(anType , anError, anUserData, anHandle *int32) int {
    cache := <- g_chanEvent
    *anType = cache.handleType
    *anHandle = cache.handle
    if 200 == cache.status {
        *anError = 0
    } else {
        *anError = int32(cache.status)
    }

    log.Println("pppp antype:", *anType, " ahdnle:", *anHandle)
    return 0
}

func CreateRequst(strMethod, strUrl, strBody string, callback unsafe.Pointer) int32 {
    req, err := http.NewRequest(strMethod, strUrl, strings.NewReader(strBody))
    nHandle := getNewHandle()

    if nil != err {
        return -1
    }

    if nil == callback {
        log.Println("CreateRequst call back is nil ")
    } else {
        //log.Println("CreateRequst call back is not nil 1111111111111111")
    }

    cache := NewHandle(nHandle, req, enum_handle_type_client, callback)

    g_mapLock.Lock()
    g_mapHandle[nHandle] = cache
    //log.Println("map:", g_mapHandle)
    g_mapLock.Unlock()
    return nHandle
}

func SetHeader(anHandle int32, astrName, astrContext string) bool {
    g_mapLock.Lock()
    cache, ok := g_mapHandle[anHandle]
    g_mapLock.Unlock()

    if ok {
        cache.Req.Header.Set(astrName, astrContext)
        return true
    }

    return false
}


func ReleaseHandle(anHandle int32) {
    //g_mapLock.Lock()
    //if _, ok := g_mapHandle[anHandle]; ok {
    //    //log.Println("xxxxxxxxxxxxxxxxddpppppddddddfffffffffff handle:", cache.handle)
    //    delete (g_mapHandle, anHandle)
    //    //log.Println("xxxxxxxxxxxxxxxxddpppppddddddfffffffffff map:", g_mapHandle)
    //} else {
    //    log.Println("xxxxxxxxxxxxxxxxddddddddfffffffffff not find:", anHandle)
    //}
    g_mapLock.Lock()
    delete (g_mapHandle, anHandle)
    g_mapLock.Unlock()
}

func dorequst(cache *HandleCache) {
    //log.Println("do client cacha.Req:", cache.Req)
    Res, err := g_client.Do(cache.Req)
    if nil == err {
        cache.status = Res.StatusCode
        defer Res.Body.Close()
        //log.Println("ssssss:", Res)
        cache.Result, err = ioutil.ReadAll(Res.Body)
        if nil != err {
            log.Println("ioutil.ReadAll err:", err)
        }
        cache.LenTotal = int32(len(cache.Result))
        if nil != cache.CallBack {
            //if 0 == cache.LenTotal {
            //    log.Println("cache.LenTotal ------------ 0 ")
            //    log.Println("=================:", len(cache.Result))
            //    log.Println("ssssssssssssss:", cache.Result)
            //    log.Println("dddddddddddddd:", Res.Body)
            //}
            C.DealRequestCallback(cache.CallBack, C.int(cache.handle), C.int(cache.status), C.CString(string(cache.Result)), C.int(cache.LenTotal))
        } else {
            g_chanEvent <- cache
        }
    } else {
        cache.status = -1
        if nil != cache.CallBack {
            C.DealRequestCallback(cache.CallBack, C.int(cache.handle), C.int(cache.status), C.CString(""), C.int(0))
        } else {
            g_chanEvent <- cache
        }

        log.Println("Error:", err)
    }
    <- g_chanCount
}

func DoRequest(anHandle int32) {
    g_chanCount <- 1
    g_mapLock.Lock()
    cache, ok := g_mapHandle[anHandle];
    g_mapLock.Unlock()

    if ok {
        go dorequst(cache)
    } else {
        log.Println("g_mapHandle not find :", anHandle)
    }
}

func GetSResult(anHandle int32) string {
    g_mapLock.Lock()
    cache, ok := g_mapHandle[anHandle]
    g_mapLock.Unlock()

    var result string
    if ok {
        log.Println("GetSResult total:", cache.LenTotal)
        result = string(cache.Result)
    } else {
        log.Println("GetResult not find handle:", anHandle)
    }

    return  result
}

func GetResult(anHandle int32) []byte {
    g_mapLock.Lock()
    cache, ok := g_mapHandle[anHandle]
    g_mapLock.Unlock()

    var result []byte
    if ok {
        result = cache.Result
    } else {
        log.Println("GetResult not find handle:", anHandle)
    }
    return result
}




